package me.yxy.mobanddd.controller;

import me.yxy.mobanddd.controller.request.command.AddTransportRequest;
import me.yxy.mobanddd.controller.request.command.AddTransportToShipmentRequest;
import me.yxy.mobanddd.controller.request.command.ModifyTransportRequest;
import me.yxy.mobanddd.controller.response.CommandResponse;
import me.yxy.mobanddd.controller.response.QueryResponse;
import me.yxy.mobanddd.domain.shipment.ShipmentFactory;
import me.yxy.mobanddd.domain.transportorder.TransportOrder;
import me.yxy.mobanddd.domain.transportorder.TransportOrderFactory;
import me.yxy.mobanddd.domain.transportorder.TransportOrderRepository;
import me.yxy.mobanddd.domain.transportorder.TransportOrderStatus;
import me.yxy.mobanddd.exception.BusinessException;
import me.yxy.mobanddd.finder.TransportOrderFinder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;

@SuppressWarnings("unused")
@RestController
@RequestMapping("/transport")
@ResponseBody
public class TransportOrderEntrance {


    /**
     * 添加一个指定运单到指定调度单中，如果未指定调度单，则直接同时创建一个新调度单
     * 这里我让Controller暂时直接扮演Application Layer
     */
    @PutMapping
    @Transactional
    public QueryResponse create(@RequestBody AddTransportRequest request){

        if(request==null)
            throw new BusinessException("参数不可为空");
        if(StringUtils.isEmpty(request.getReceiverLocation()))
            throw new BusinessException("收货人地址不可为空");

        TransportOrder newTransportOrder = transportOrderFactory.createByRequest(request);

        //TODO 需要完善一下公共Response
        return QueryResponse.ok(newTransportOrder.getId());
    }

    @PostMapping("/modify")
    @Transactional
    public CommandResponse modify(@RequestBody ModifyTransportRequest request){

        if(request.getTransportId()==null){
            throw new BusinessException("运单ID不能为空");
        }

        Optional<TransportOrder> transportOrderOptional = transportOrderRepository.findById(request.getTransportId());
        TransportOrder transportOrder = transportOrderOptional.orElseThrow(()->new BusinessException("该运单不存在"));
        transportOrder.modifyBrief(request);
        return CommandResponse.ok();
    }


    /**
     * 完全删除一个运单
     * @param id
     */
    @DeleteMapping(value = "/{id}")
    public void remove(@PathVariable("id") Long id){

        //首先找出这个运单
        Optional<TransportOrder> orderOption = transportOrderRepository.findById(id);
        TransportOrder transportOrder = orderOption.orElseThrow(()->new BusinessException("运输单不存在"));

        //------然后进入商业逻辑----------由于非常简单，所以直接在应用层写逻辑了
        //必须要先从调度单中移除关联后才能删除
        //注意，在这里，TransportOrder这个DomainEntity需要带上Status，所以把status属性要加到Domain中
        if(transportOrder.getStatus() != TransportOrderStatus.INIT){
            throw new BusinessException("只有待配送状态的运单才允许删除");
        }

        //执行删除
        transportOrder.remove();

    }








    /**
     * 添加一个指定运单到指定调度单中，如果未指定调度单，则直接同时创建一个新调度单
     * 这里我让Controller暂时直接扮演Application Layer
     */
    @PutMapping(value = "/addToShipment")
    @Transactional
    public void addTransportToShipment(@RequestBody AddTransportToShipmentRequest request){

        //----------
        if(request==null)
            throw new BusinessException("参数不可为空");
        if(request.getTransportOrderId()==null)
            throw new BusinessException("运单参数不可为空");
        //---------


        //根据orderId获取运单
//        TransportOrder transportOrder = transportOrderFinder.findById(request.getTransportOrderId());
//
//        //如果传入了调度单ID，则获取，否则，创建调度单
//        Shipment shipment;
//        if(ObjectUtils.isEmpty(request.getShipmentId())){
//            shipment = shipmentFactory.create();
//        }else{
//            shipment = shipmentFinder.findById(request.getShipmentId());
//        }

        //调度单加入运单
        /*
            这里有一个思考点：
            到底应该是“shipment.addTransportOrder(order)" 还是 "transportOrder.bindShipment(shipment)呢？"
            技术上来说，当然都能满足功能，只是以目前关系型数据库的设计模式来说，更倾向于后者
            所以，在这里约定一个规范：
            一（A）对多（B）的场景下，非特殊情况，都以A作为动作发起方：A “绑定” B，当然“绑定”二字可以换成其他业务术语

            顺便再扩展一下：
            一对一： 分析两者的主次，谁是业务核心，则由谁来驱动，比如User与User_detail，当然User才是核心，detail一看就是再其基础上做的业务扩展
            多对多：建议从数量入手，数量大的那一方作为驱动方，比如“用户”与“感兴趣的类目”，当然用户数量比类目数量远远要大，所以由 “用户 绑定 类目”
                    如果数量相当，则说明业务上本来就是无主次之分，则可以具体情况再分析了，但这种场景不多，一般都会有主次
         */
//        transportOrder.bindShipment(shipment);

    }








    @Autowired
    TransportOrderFactory transportOrderFactory;


    @Autowired
    TransportOrderFinder transportOrderFinder;

    @Autowired
    TransportOrderRepository transportOrderRepository;

    @Autowired
    ShipmentFactory shipmentFactory;
}
